home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 21 / Mac Magazin and MacEasy Magazine CD - Issue 21.iso / Wissenschaft & Technik / yorick12vr1-nofpu folder / include / mkdoc.i < prev    next >
Text File  |  1995-07-26  |  7KB  |  267 lines

  1. /*
  2.    MKDOC.I
  3.    Alphabetize DOCUMENT comments and prepare for line printer.
  4.  
  5.    $Id: mkdoc.i,v 1.1 1993/08/27 18:50:06 munro Exp $
  6.  */
  7. /*    Copyright (c) 1994.  The Regents of the University of California.
  8.                     All rights reserved.  */
  9.  
  10. func mkdoc(filename, outname, lpp)
  11. /* DOCUMENT mkdoc, filename
  12.          or mkdoc, filename, outname, lpp
  13.      alphabetizes and indexes the DOCUMENT comments in FILENAME, and
  14.      formats into "dictionary-like" pages for printing.  If OUTNAME
  15.      is not given or nil, the output file will be FILENAME with ".doc"
  16.      replacing the ".i".  If LPP is not given, it defaults to 58 --
  17.      the maximum number of available lines per page of output.
  18.      (Use 55 to be able to print with "lpr -p" style page headings.)
  19.      FILENAME can be an array of strings to combine several include
  20.      files into a single document.
  21.    SEE ALSO: help
  22.  */
  23. {
  24.   extern mkdoc_lpp;
  25.  
  26.   if (is_void(lpp)) mkdoc_lpp= 58;
  27.   else mkdoc_lpp= lpp;
  28.   name_list= doc_list= oname= [];
  29.   inames= filename;
  30.  
  31.   for (ii=1 ; ii<=numberof(filename) ; ii++) {
  32.     f= open(filename(ii));
  33.  
  34.     /* strip off non-directory part of filename */
  35.     name= [string(0), filename(ii)];
  36.     do {
  37.       name= strtok(name(2), "/\:");
  38.     } while (name(2));
  39.     name= name(1);
  40.     inames(ii)= name;
  41.  
  42.     /* get output file name */
  43.     if (is_void(oname)) {
  44.       if (is_void(outname)) {
  45.     oname= name;
  46.     if (strpart(oname, -1:0)==".i") oname= strpart(oname, 1:-2);
  47.     oname+= ".doc";
  48.       } else {
  49.     oname= outname;
  50.       }
  51.     }
  52.  
  53.     /* scan the file to accumulate lists of function/variable/keyword names
  54.        and the corresponding document strings */
  55.     mkdoc_scan, f;
  56.     close, f;
  57.   }
  58.  
  59.   /* alphabetize the lists */
  60.   order= sort(name_list);
  61.   name_list= name_list(order);
  62.   doc_list= doc_list(order);
  63.  
  64.   /* make the title page */
  65.   f= open(oname, "w");
  66.   mkdoc_title, f, inames, name_list;
  67.  
  68.   n= numberof(name_list);
  69.   fragment= [];
  70.   /* loop on output pages */
  71.   while ((nlines= numberof(fragment)) || n) {
  72.     nleft= mkdoc_lpp-3;  /* leave 3 lines for heading */
  73.     if (nlines) {
  74.       /* part of the last entry has spilled onto the new page */
  75.       if (nlines < nleft) {
  76.     /* ...it fits on this page */
  77.     page= fragment;
  78.     fragment= [];
  79.     nleft-= nlines;
  80.       } else {
  81.     /* ...it fills this page completely, too --
  82.        be sure at least 6 lines on next page */
  83.     if (nlines < nleft+6) {
  84.       page= fragment(1:-6);
  85.       fragment= fragment(-5:0);
  86.     } else {
  87.       page= fragment(1:nleft);
  88.       fragment= fragment(nleft+1:0);
  89.     }
  90.     mkdoc_page, f, name, name, page;
  91.     continue;
  92.       }
  93.       fname= name;
  94.       not_top= 1;
  95.     } else {
  96.       page= [];
  97.       fname= name_list(1);
  98.       not_top= 0;
  99.     }
  100.  
  101.     /* loop on entries for this page */
  102.     while (n) {
  103.       oname= name;
  104.       name= name_list(1);
  105.       fragment= *doc_list(1);
  106.       nlines= 1+numberof(fragment);
  107.       if (nleft >= nlines+not_top) {
  108.     /* this entire entry fits on this page */
  109.     if (not_top) grow, page, "";
  110.     grow, page, swrite(format="%75s", name), fragment;
  111.     fragment= [];
  112.     nleft-= nlines+not_top;
  113.       } else if (nlines+not_top>7 && nleft>7 &&
  114.          (nlines-nleft>=6 || nlines>12)) {
  115.     /* this entry runs over onto following pages */
  116.     if (not_top) grow, page, "";
  117.     nleft-= 1+not_top;
  118.     if (nlines-nleft<6) nlines-= 6;
  119.     else nlines= nleft;
  120.     grow, page, swrite(format="%75s", name), fragment(1:nlines);
  121.     fragment= fragment(nlines+1:);
  122.     nleft= 0;
  123.       } else {
  124.     /* this entire entry goes on next page */
  125.     name= oname;
  126.     fragment= [];
  127.     break;
  128.       }
  129.       if (--n) {
  130.     name_list= name_list(2:);
  131.     doc_list= doc_list(2:);
  132.       }
  133.       if (nleft<3 || numberof(fragment)) break;
  134.       not_top= 1;
  135.     }
  136.  
  137.     /* output this page with dictionary headings */
  138.     mkdoc_page, f, fname, name, page;
  139.   }
  140.  
  141.   close, f;
  142. }
  143.  
  144. func mkdoc_scan(f)
  145. {
  146.   /* Add extern, local, func, and struct declaration/definition names to
  147.      the name_list.  For extern and func, add the DOCUMENT comment to the
  148.      doc_list.  If no DOCUMENT comment appears within 10 non-blank lines,
  149.      skip to the next extern or func.  If subsequent extern lines precede
  150.      the DOCUMENT comment, generate a cross-reference SEE ... to the
  151.      first extern of the group.  For struct, the entire struct definition,
  152.      which is presumably commented, becomes the documentation text.  */
  153.   extern name_list, doc_list;
  154.  
  155.   while (line= rdline(f)) {
  156.  
  157.     split= strtok(line);
  158.     doctext= [];
  159.  
  160.     if (split(1)=="func" || split(1)=="extern" || split(1)=="local") {
  161.       name= strtok(split(2), " \t(,;");
  162.       if (split(1)!="local") crossref= [];
  163.       else crossref= mkdoc_cross(1, name(2), []);
  164.       name= name(1);
  165.       count= 10;        /* like help_worker function defined in std.i */
  166.       while ((line= rdline(f)) && count--) {
  167.     split= strtok(line);
  168.     if (!split(1)) break;
  169.     if (strmatch(line, "/* DOCUMENT")) {
  170.       do {
  171.         grow, doctext, [line];
  172.         if (strmatch(line, "*/")) break;
  173.       } while (line= rdline(f));
  174.     } else if (split(1)=="extern") {
  175.       crossref= mkdoc_cross(0, split(2), crossref);
  176.       if (count==9) count= 10;
  177.     } else if (split(1)=="local") {
  178.       crossref= mkdoc_cross(1, split(2), crossref);
  179.       if (count==9) count= 10;
  180.     }
  181.       }
  182.  
  183.     } else if (split(1)=="struct") {
  184.       name= strtok(split(2), " \t(,;")(1);
  185.       gotopen= 0;
  186.       do {
  187.     grow, doctext, [line];
  188.     if (!gotopen) gotopen= strmatch(line, "{");
  189.     if (gotopen && strmatch(line, "}")) break;
  190.       } while (line= rdline(f));
  191.       crossref= [];
  192.     }
  193.  
  194.     if (!is_void(doctext)) {
  195.       grow, name_list, [name];
  196.       grow, doc_list, [&doctext];
  197.       n= numberof(crossref);
  198.       for (i=1 ; i<=n ; i++) {
  199.     grow, name_list, crossref(i);
  200.     grow, doc_list, &["    /* SEE "+name+"     */"];
  201.       }
  202.     }
  203.   }
  204. }
  205.  
  206. func mkdoc_cross(loc, names, crossref)
  207. {
  208.   split= strtok(names, " \t,;");
  209.   cross= crossref;
  210.   while (split(1) && !strmatch(split(1), "/*")) {
  211.     grow, cross, split(1:1);
  212.     if (!loc) break;
  213.     split= strtok(split(2), " \t,;");
  214.   }
  215.   return cross;
  216. }
  217.  
  218. func mkdoc_title(f, inames, name_list)
  219. {
  220.   extern mkdoc_lpp;
  221.  
  222.   write, f, format="\n\n\n"+
  223.     "                          Yorick Documentation\n"+
  224.     "                for functions, variables, and structures\n"+
  225.     "                         defined in file %s\n"+
  226.     "                   Printed: %s\n", inames(1), timestamp();
  227.  
  228.   write, f, format="\n   %s\n\n", "Contents:";
  229.  
  230.   nleft= mkdoc_lpp-10;
  231.  
  232.   n= numberof(name_list);
  233.   ncols= 1;
  234.   while (n/ncols > nleft-3) ncols++;
  235.   width= 80/ncols;
  236.   len= max(strlen(name_list));
  237.   if (len > width-3) {
  238.     /* Contents will overflow onto subsequent page(s).  Hopefully rare.  */
  239.     ncols= 80/(len+3);
  240.     width= 80/ncols;
  241.   }
  242.  
  243.   format= (width-len)/2 + 1;
  244.   width-= format;
  245.   format= swrite(format="%"+print(format)(1)+"s", "");  /* leading blanks */
  246.   format= format+"%-"+print(width)(1)+"s";           /* e.g.- "    %-12s" */
  247.  
  248.   len= (n-1)/ncols + 1;
  249.   for (i=1 ; i<=len ; i++) {
  250.     line= "";
  251.     for (j=i ; j<=n ; j+= len) line+= swrite(format=format, name_list(j));
  252.     j= strlen(line);
  253.     while (strpart(line, j:j)==" ") j--;
  254.     write, f, format="%s", strpart(line, 1:j)+"\n";
  255.   }
  256. }
  257.  
  258. func mkdoc_page(f, fname, name, page)
  259. {
  260.   extern mkdoc_lpp;
  261.  
  262.   write, f, format="\f\n%75s\n\n", swrite(format="FROM %s TO %s",
  263.                       fname, name);
  264.   n= numberof(page);
  265.   for (i=1 ; i<=n ; i++) write, f, format="%s\n", page(i);
  266. }
  267.